package recursiveDescent.parse;

import java.util.Map;
import java.util.Map.Entry;

import util.ParseUtils;
import util.SysConstant;

public class ParseConfig {
	private char[] codes ;
	private Map<String, String> expMap;
	private int i = 0;
//	private int row = 0;
	private int len = 0;
	//当前算数表达式是否可识别
	private boolean flag = true;
	//当前状态 0开始  -> 1(输入数字) -> 输入(.) -> 2(小数)  3end 
	private int state = 0;
	private double curNum;
	private int returnVal;
	//词法分析
	public ParseConfig(Map<String, String> expMap) {
		this.expMap = expMap;
//		this.quatriples = new ArrayList<>();
	}
	
	//状态转移函数
	public int move(int state, char ch) {
		//初始->整数
		if (ParseUtils.isDigit(ch)) {
			return state == 0 ? 1 : state;
		//整数->小数
		} else if (state == 1 && ch == '.') {
			return 2;
		//结束状态
		} else if ((state == 1 || state == 2) && (ParseUtils.isOps(ch) || ch == '$')) {
			i--;
			return 3;
		//错误状态
		} else {
			//System.out.println(ch);
			return 0;
		}
	}
	
	//分词器记录当前的十进制数字串
	//true 分词正确   false 分词错误或者分词结束
	public int lexer() {
		if (i == len || codes[i] == '$')
			return SysConstant.END;
		if (ParseUtils.isEnd(codes[i])) {
			i++;
			//返回非数字运算符 如括号
			//System.out.println(codes[i - 1]);
			return codes[i-1];
		}
		int j = i;
		while (i < len) {
			//根据状态做不同的处理
			this.state = move(this.state, codes[i++]);
			//语法错误
			if (this.state == 0) return SysConstant.ERR;
			else if (state == 3) {
				double res = 0;
				//调试: System.out.println("当前状态符号" + codes[i]);
				String temp = new String(codes);
				if (ParseUtils.isDigit(codes[i])) {
					//处理后半部分无法识别多位数的问题 新的问题:处理中间多位数问题 
					int step = temp.length() - 1 - j;
					res = Double.valueOf(temp.substring(j, temp.length() - 1));
					i += step;
				}
				else
					res = Double.valueOf(temp.substring(j, i));
				this.curNum = res;
				//调试: System.out.println(curNum + "===>" + i);
				return SysConstant.NUM;
			}
		}
		return 0;
		
		
	}
	
	public void analyze() {
		boolean test = false;
		for (Entry<String, String> entry : expMap.entrySet()) {
			this.i = 0;
			this.flag = true;
			this.codes = entry.getKey().toCharArray();
			this.len = codes.length;
			
			//初始化状态
			this.state = 0;
			this.returnVal = lexer();
			
			double res = exp();
			//int intRes = 0;
			if (entry.getKey().indexOf('/') != -1 || entry.getKey().indexOf('.') != -1) {
				test = true;
			} 
			
			//System.out.println("计算结果" + res);
			if (flag) {
				expMap.put(entry.getKey(), test == true ? 
											String.valueOf(res) :
											String.valueOf( (int)res) );
			} else {
				expMap.put(entry.getKey(), SysConstant.ERROR);
			}
			test = false;
		}
	}
	
	public void match(int type) {
		//System.out.println(returnVal);
		if (returnVal == type) {
			returnVal = lexer();
		} else {
			flag = false;
		}
	}
	
	
	//表达式  exp -> term expTemp
	public double exp()  {
		
		switch (returnVal) {
			case SysConstant.NUM:
			case '-':
			case '(':
				return term() + expTemp();
		default:
			flag = false;
			return 0;
		}
		
		//return expTemp();
	}
	
	//expTemp -> addop term expTemp | end
	public double expTemp()  {
		//expTemp -> addop term expTemp
		//System.out.println("expTemp " + returnVal);
		switch (returnVal) {
			case '+':
				match('+');
				double result = term() + expTemp();
				//System.out.println("检测到加法:" + result);
				return result;
			case ')':
			case SysConstant.END:
				return 0;
			case '-':
				match('-');
				return -(term() - expTemp());	
			

		default:
			flag = false;
			return 0;
		}
		
		
	}

	
	//项 term -> factor termTemp
	public double term()  {
		//System.out.println("term " + returnVal);
		switch (returnVal) {
			case SysConstant.NUM:
			case '-':
			case '(':
				double factor = factor();
				double t = termTemp();
				return factor * t;
		default:
			flag = false;
			return 0;
		}
		
	}
	
	//项 tempTemp -> mulOp factor tempTemp | null
	public double termTemp()  {
		//System.out.println("termtemp " + returnVal);
		switch (returnVal) {
			//case SysConstant.NUM:
			case '+':
			case '-':
			case SysConstant.END:
			case ')':
				return 1;
			case '*':
				match('*');
				return factor() * termTemp();
			case '/':
				match('/');
				return 1 / ( factor() / termTemp());
		default:
			flag = false;
			return 0;
			
		}
		
		
	}
	
	
	//因子 factor -> ( exp ) | number 
	public double factor()  {
		//double result = 0d;
		//System.out.println("factor " + returnVal);
		switch (returnVal) {
		
		case '-':
			match('-');
			return -num();
		case SysConstant.NUM:
		case '(':
			return num();
		default:
			flag = false;
			return 0;
			
		}
		
	} 
	
	
	
	private double num() {
		//System.out.println("end " + returnVal);
		double temp;
		switch (returnVal) {
	
		case SysConstant.NUM:
			temp = curNum;
			match(SysConstant.NUM);
			return temp;
		case '(':
			match('(');
			temp = exp();
			match(')');
			return temp;
		default:
			flag =false;
			return 0;
		}
		
//		double m,n_;
//		switch (returnVal) {
//		case SysConstant.NUM:
//		case '(':
//			m = end();
//			n_ = numTerm();
//			return Math.pow(m, n_);
//		default:
//			flag = false;
//			return 0;
//		}
		
	}


	private double numTerm() {
		switch (returnVal) {
		case '+':
		case '-':
		case '*':
		case '/':
		case ')':
		case SysConstant.END:
			return 1;
		case '^':
			match('^');
			return num();
		default:
			flag = false;
			return 0;
		}
		
	}

	private double end() {
		double temp;
		switch (returnVal) {
	
		case SysConstant.NUM:
			temp = curNum;
			match(SysConstant.NUM);
			return temp;
		case '(':
			match('(');
			temp = exp();
			match(')');
			return temp;
		default:
			flag =false;
			return 0;
		}
	}


	public Map<String, String> getExpMap() {
		return expMap;
	}
}
